﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Threading;
using System.Drawing;
using PluginInterfacesLib;

namespace SoundPlugin
{
    public sealed class PluginModel : INotifyPropertyChanged
    {
        private static readonly ReaderWriterLock rwlock = new ReaderWriterLock();
        private static List<Spat> markerPositions;
        private static readonly ReaderWriterLockSlim markerPositionsLock = new ReaderWriterLockSlim();
        public List<Spat> MarkerPositions
        {
            get 
            {
                try
                {
                    markerPositionsLock.EnterReadLock();
                    return PluginModel.markerPositions;
                }
                finally 
                {
                    markerPositionsLock.ExitReadLock();
                }
            }
            set 
            {
                try
                {
                    markerPositionsLock.EnterWriteLock();
                    PluginModel.markerPositions = value;
                }
                finally 
                {
                    markerPositionsLock.ExitWriteLock();
                }
            }
        }
        private static Bitmap _image;
        public event PropertyChangedEventHandler PropertyChanged;
        private static Boolean _colorMarkerProcessorResultReceived;
        private static ColorMarkerProcessor colorMarkerProcessor;
        private static Thread colorMarkerProcessorThread;
        private static readonly PluginModel instance = new PluginModel();
        private static Bitmap markerImage;
        private static IPluginHost host;
        private static SoundPlugin plugin;
        private static bool runThread;

        public bool RunThread
        {
            get { return PluginModel.runThread; }
            set { PluginModel.runThread = value; }
        }

        public SoundPlugin Plugin
        {
            get { return PluginModel.plugin; }
            set { PluginModel.plugin = value; }
        }

        public IPluginHost Host
        {
            get { return PluginModel.host; }
            set { PluginModel.host = value; }
        }

        public Boolean ColorMarkerProcessorResultReceived
        {
            get { return _colorMarkerProcessorResultReceived; }
            set { _colorMarkerProcessorResultReceived = value; }
        }

        public ColorMarkerProcessor ColorMarkerProcessor
        {
            get { return colorMarkerProcessor; }
            set { colorMarkerProcessor = value; }
        }

        public Bitmap MarkerImage
        {
            get
            {
                return new Bitmap(markerImage);

            }
            set
            {

                markerImage = value;
                if (value != null)
                {
                    OnPropertyChanged(this, new PropertyChangedEventArgs("MarkerImage"));
                }

            }
        }

        public Bitmap Image
        {

            get
            {
                rwlock.AcquireReaderLock(10000);
                try
                {
                    return _image;
                }
                finally
                {
                    rwlock.ReleaseReaderLock();
                }
            }
            set
            {
                rwlock.AcquireWriterLock(10000);
                try
                {
                    _image = value;
                    if (value != null)
                    {
                        OnPropertyChanged(this, new PropertyChangedEventArgs("Image"));
                        colorMarkerProcessor.HandleEvent(this, EventArgs.Empty);
                    }
                }
                finally
                {
                    rwlock.ReleaseWriterLock();
                }
            }
        }

        private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(sender, e);
            }
        }

        public static PluginModel Instance
        {
            get
            {
                return PluginModel.instance;
            }
        }

        public PluginModel()
        {         
            List<Spat> spats = new List<Spat>();
            Spat spat = new Spat(Color.FromArgb(217, 151, 79), 30.0);
            Spat spat1 = new Spat(Color.FromArgb(83, 183, 123), 30.0);
            spats.Add(spat);
            spats.Add(spat1);
            this.MarkerPositions = new List<Spat>(spats.Count);
            colorMarkerProcessor = new ColorMarkerProcessor(spats);
            colorMarkerProcessor.ThreadRun = true;
            colorMarkerProcessorThread = new Thread(new ThreadStart(colorMarkerProcessor.Run));
            colorMarkerProcessor.NewResult += this.MarkerProcessorResultReceived;
            markerImage = ImageProcessing.NewEmptyImage(320, 240, Color.Black);
            _image = ImageProcessing.NewEmptyImage(320, 240, Color.Black);
        }

        public void MarkerProcessorResultReceived(object sender, EventArgs args)
        {
            ColorMarkerProcessorResultReceived = true;
        }

        public void ThreadRun()
        {
            Thread.Sleep(1000);
            while (runThread)
            {

                Bitmap image = (Bitmap)host.GetWebcamImage();
                //image.RotateFlip(RotateFlipType.RotateNoneFlipX);
                PluginModel.Instance.Image = image;

                if (!colorMarkerProcessorThread.IsAlive && colorMarkerProcessorThread.ThreadState != ThreadState.Stopped)
                {
                    colorMarkerProcessorThread.Start();
                }

                if (_colorMarkerProcessorResultReceived)
                {
                    PluginModel.Instance.MarkerImage = colorMarkerProcessor.MarkerImage;
                    PluginModel.Instance.MarkerPositions = colorMarkerProcessor.Spats;

                    if (PluginModel.Instance.MarkerPositions != null)
                    {
                        if (PluginModel.Instance.Plugin != null) 
                        {
                            foreach (Spat spat in PluginModel.Instance.MarkerPositions)
                            {
                                Point? center = spat.getCenter();
                                if (center != null) 
                                {
                                    //PluginModel.Instance.Plugin.CheckButtons((Point)center);
                                }
                            }
                        }
                    }
                    _colorMarkerProcessorResultReceived = false;
                }
                Thread.Sleep(100);

            }
            PluginModel.Instance.ColorMarkerProcessor.ThreadRun = false;
        }

    }
}
